package com.chinackts.proceedspayment.importpayment.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chinackts.auth.model.MenuManagerType;
import com.chinackts.auth.model.RdTime;
import com.chinackts.auth.repository.redis.SocialCreditCodeRepository;
import com.chinackts.auth.service.HeaderStoreService;
import com.chinackts.auth.service.MenuManagerService;
import com.chinackts.auth.service.MenuTypeService;
import com.chinackts.auth.service.RdTimeService;
import com.chinackts.common.exception.ApplicationException;
import com.chinackts.common.filestorage.EPortFileStorageService;
import com.chinackts.common.filestorage.StorageModule;
import com.chinackts.common.okhttp.OkHttpRequest;
import com.chinackts.common.utils.ErrorMsgUtil;
import com.chinackts.common.utils.MonthDivider;
import com.chinackts.proceedspayment.importpayment.dto.ImportPaymentListDto;
import com.chinackts.proceedspayment.importpayment.query.ImportPaymentPageQuery;
import com.chinackts.proceedspayment.importpayment.query.ImportPaymentQuery;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.zhoujianhui.filestorage.model.FileContent;
import org.zhoujianhui.filestorage.model.FileMetaInfo;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

/**
 * @author Lianhong
 * @since 2021/11/18
 */
@Service
public class ImportPaymentService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ImportPaymentService.class);

    //进口付汇列表
    private static final String IMPORT_PAYMENT_LIST_URL = "https://i.chinaport.gov.cn/fecwebserver//gpi/queryList";
    //进口付汇明细
    private static final String IMPORT_PAYMENT_DETAIL_URL = "https://i.chinaport.gov.cn/fecwebserver//gpi/getshowview.c";
    //进口付汇PDF
    private static final String IMPORT_PAYMENT_PDF_URL = "https://i.chinaport.gov.cn/fecwebserver/gpi/ImportPrint.pdf";

    @Resource(name = "proxyOkHttpRequest")
    private OkHttpRequest request;
    @Resource
    private HeaderStoreService headerStoreService;
    @Resource
    private RdTimeService rdTimeService;
    @Resource
    private MenuTypeService menuTypeService;
    @Resource
    private ImportPaymentStoreService importPaymentStoreService;
    @Resource
    private EPortFileStorageService ePortFileStorageService;
    @Resource
    private SocialCreditCodeRepository socialCreditCodeRepository;
    @Resource
    private MenuManagerService menuManagerService;

    public ImportPaymentListDto list(String id, ImportPaymentQuery query) {
        //获取fec rdtime，并添加至请求头
        rdTimeService.fecRdTimeRequestAndStore(id);
        headerStoreService.setRdTimeHeader(id, RdTime.Fec);
        //fec解密js
//        menuTypeService.menuTypeRequestAndStore(id, MenuType.Fec);
        menuManagerService.menuManagerRequestAndStore(id, MenuManagerType.Fec);
        try {
            if (StringUtils.isNotBlank(query.getEntryId())) {
                return this.importPaymentList(id, query, 0, 10);
            }
            String beginDate = query.getSaveDateFrom();
            String endDate = query.getSaveDateTo();
            if (StringUtils.isAllBlank(beginDate, endDate)) {
                throw new ApplicationException("请提供开始和截止日期");
            }
            List<String[]> months = MonthDivider.divide(beginDate, endDate);
            int pageSize = 500;
            ImportPaymentListDto result = new ImportPaymentListDto();
            for (String[] item : months) {
                int pageNo = 1;
                query.setSaveDateFrom(item[0]);
                query.setSaveDateTo(item[1]);
                ImportPaymentListDto items = this.importPaymentList(id, query, 0, pageSize);
                result.addRows(items.getRows());
                int totalPage = (items.getTotal() + pageSize - 1) / pageSize;
                while (totalPage > pageNo) {
                    pageNo++;
                    result.addRows(this.importPaymentList(id, query, (pageNo - 1) * pageSize, pageSize).getRows());
                }
            }
            result.setTotal(result.getRows().size());
            return result;
        } catch (Exception e) {
            LOGGER.error("电子口岸进口付汇报关单采集失败 ", e);
            throw new RuntimeException(String.format("电子口岸进口付汇报关单采集失败：%s", ErrorMsgUtil.getErrorMsg(e)));
        }
    }

    public ImportPaymentListDto pageList(String id, ImportPaymentPageQuery query) {
        //获取fec rdtime，并添加至请求头
        rdTimeService.fecRdTimeRequestAndStore(id);
        headerStoreService.setRdTimeHeader(id, RdTime.Fec);
        //fec解密js
//        menuTypeService.menuTypeRequestAndStore(id, MenuType.Fec);
        menuManagerService.menuManagerRequestAndStore(id, MenuManagerType.Fec);
        if (StringUtils.isNotBlank(query.getEntryId())) {
            return this.importPaymentList(id, query, 0, 10);
        }
        Integer pageSize = query.getPageSize();
        return this.importPaymentList(id, query, (query.getPageNo() - 1) * pageSize, pageSize);
    }

    private ImportPaymentListDto importPaymentList(String id, ImportPaymentQuery query, int offset, int limit) {
        JSONObject queries = new JSONObject();
        queries.put("limit", limit);
        queries.put("offset", offset);
        queries.put("entryId", StringUtils.isEmpty(query.getEntryId()) ? StringUtils.EMPTY : query.getEntryId());
        queries.put("saveDateFrom", StringUtils.isEmpty(query.getSaveDateFrom()) ? StringUtils.EMPTY : query.getSaveDateFrom());
        queries.put("saveDateTo", StringUtils.isEmpty(query.getSaveDateTo()) ? StringUtils.EMPTY : query.getSaveDateTo());
        queries.put("_", DateTime.now().getMillis());
        String response = request.get(IMPORT_PAYMENT_LIST_URL, queries);
        if (StringUtils.isBlank(response)) throw new ApplicationException("未采集到进口付汇列表，请重试。");

//        response = menuTypeService.decode(id, response, MenuType.Fec);
        response = menuManagerService.decode(id, response, MenuManagerType.Fec);
        ImportPaymentListDto importPaymentList = JSON.parseObject(response, ImportPaymentListDto.class);
        if (CollectionUtils.isEmpty(importPaymentList.getRows())) return importPaymentList;
        List<String> resultList = importPaymentStoreService.exists(importPaymentList.getRows());
        LOGGER.info(String.format("共%s条数据，其中%s条数据已入库", importPaymentList.getRows().size(), resultList.size()));
        importPaymentList.getRows().forEach(item -> item.put("stored", resultList.contains(item.getString("entryId"))));
        return importPaymentList;
    }

    public JSONObject details(String id, String entryId, boolean regather) {
        //海关仓库是否已存在进口付汇明细
        boolean exists = importPaymentStoreService.exists(entryId);
        if (exists && !regather) {
            return importPaymentStoreService.get(entryId);
        }
        //获取fec rdtime，并添加至请求头
        rdTimeService.fecRdTimeRequestAndStore(id);
        headerStoreService.setRdTimeHeader(id, RdTime.Fec);
        //fec解密js
//        menuTypeService.menuTypeRequestAndStore(id, MenuType.Fec);
        menuManagerService.menuManagerRequestAndStore(id, MenuManagerType.Fec);
        JSONObject queries = new JSONObject();
        queries.put("entryId", entryId);
        queries.put("_", DateTime.now().getMillis());
        String response = request.get(IMPORT_PAYMENT_DETAIL_URL, queries);
        if (StringUtils.isBlank(response)) throw new ApplicationException("未采集到进口付汇明细，请重试。");
//        response = menuTypeService.decode(id, response, MenuType.Fec);
        response = menuManagerService.decode(id, response, MenuManagerType.Fec);
        JSONObject importPayment = JSON.parseObject(response);

        if (importPayment.getBoolean("success")) {
            importPaymentStoreService.save(new JSONObject() {{
                put("entryId", entryId);
                put("socialCreditCode", socialCreditCodeRepository.getSocialCreditCode(id));
                put("importPayment", importPayment);
            }});
        } else {
            LOGGER.info("采集进口付汇联数据失败：{}", importPayment);
        }
        //存储海关数据仓库
        return importPayment;
    }

    public void exportProceedsPdf(String id, List<String> entryIds, HttpServletResponse response) {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            //查询多文件时，暂不做存储（无法对应关单号与文件的关联）
            if (entryIds.size() == 1) {
                String entryId = entryIds.get(0);
                //文件是否已存储
                boolean stored = importPaymentStoreService.stored(entryId);
                if (stored) {
                    //响应已存储文件
                    String storedFile = importPaymentStoreService.storedFile(entryId);
                    String[] storedFileArr = storedFile.split("/");
                    FileContent content = ePortFileStorageService.load(StorageModule.IMPORT_PAYMENT, storedFileArr[storedFileArr.length - 1]);
                    inputStream = content.getData();
                    IOUtils.copy(inputStream, outputStream);
                    return;
                }
            }
            byte[] bytes = request.postBytes(IMPORT_PAYMENT_PDF_URL, new JSONObject() {{
                put("printenEntryId", StringUtils.join(entryIds, ","));
            }});
            if (bytes == null) {
                throw new ApplicationException("未下载到进口付汇PDF，请重试。");
            }
            if (entryIds.size() == 1) {
                String entryId = entryIds.get(0);
                //保存文件
                FileMetaInfo fileInfo = ePortFileStorageService.store(StorageModule.IMPORT_PAYMENT, String.format("%s.pdf", entryId), bytes);
                importPaymentStoreService.saveFile(StorageModule.IMPORT_PAYMENT, entryId, fileInfo.getStorageName());
            }
            inputStream = new ByteArrayInputStream(bytes);
            IOUtils.copy(inputStream, outputStream);
        } catch (Exception e) {
            LOGGER.error("进口付汇PDF下载异常", e);
            throw new ApplicationException("进口付汇PDF下载异常");
        } finally {
            try {
                if (outputStream != null) outputStream.flush();
                IOUtils.closeQuietly(inputStream);
                IOUtils.closeQuietly(outputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
